home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Compression / Opener / Source / utils / mcvert / hqxify.c next >
Encoding:
C/C++ Source or Header  |  1994-03-03  |  19.8 KB  |  598 lines

  1. /* This has been hacked to extract only the data fork, not store it
  2.       as Macbinary file.
  3.    Lines commented out or modified are noted by "## io ##"
  4.    [Izumi Ohzawa, 94-03-02]
  5. */
  6.  
  7.  
  8.  
  9. #include "mactypes.h"
  10.  
  11. #define HQXBUFLEN 512
  12. byte hqxbuf[HQXBUFLEN+1], *buf_ptr, *buf_end, *buf_start=hqxbuf+1;
  13.  
  14. #define MAXLINE 255
  15. byte line[MAXLINE+1], *line_ptr, *line_end, *line_start=line+1;
  16.  
  17. int line_count, file_count;
  18. int save_state, total_bytes, save_run_length;
  19. word save_nibble;
  20. char binfname[BINNAMELEN], hqxfname[BINNAMELEN];
  21. FILE *hqxfile, *binfile;
  22.  
  23. /* This routine reads the header of a hqxed file and appropriately twiddles it,
  24.     determines if it has CRC problems, creates the .bin file, and puts the info
  25.     into the .bin file.
  26.     Output is hqx_datalen, hqx_rsrclen, type, binfname, binfile */
  27.  
  28. hqx_to_bin_hdr(type, hqx_datalen, hqx_rsrclen)
  29. char *type;
  30. ulong *hqx_datalen, *hqx_rsrclen;
  31. {   register byte *hqx_ptr, *hqx_end;
  32.     register ulong calc_crc;
  33.     hqx_buf *hqx_block;
  34.     hqx_header *hqx;
  35.     info_header info;
  36.     ulong mtim;
  37.     short crc;
  38.  
  39.     extern word magic[];
  40.     extern FILE *verbose;
  41.     extern char *dir, *ext;
  42.     extern short calc_mb_crc();
  43.  
  44.     /* read the hqx header, assuming that I won't exhaust hqxbuf in so doing */
  45.     fill_hqxbuf();
  46.     hqx_block = (hqx_buf *) buf_ptr;
  47.     hqx = (hqx_header *) (hqx_block->name + hqx_block->nlen);
  48.     hqx_ptr = buf_ptr;
  49.     hqx_end = (byte *) hqx + sizeof(hqx_header) - 1;
  50.     calc_crc = 0;
  51.     while (hqx_ptr < hqx_end)
  52.         calc_crc = (((calc_crc&0xff) << 8) | *hqx_ptr++) ^ magic[calc_crc >> 8];
  53.     calc_crc = ((calc_crc&0xff) << 8) ^ magic[calc_crc >> 8];
  54.     calc_crc = ((calc_crc&0xff) << 8) ^ magic[calc_crc >> 8];
  55.     buf_ptr = hqx_ptr;
  56.  
  57.     /* stuff the hqx header data into the info header */
  58.     bzero(&info, sizeof(info_header));
  59.     info.nlen = hqx_block->nlen;
  60.     strncpy(info.name, hqx_block->name, info.nlen);     /* name */
  61.     bcopy(hqx->type, info.type, 9);             /* type, author, flag */
  62.     info.flags  &= 0x7e;                        /* reset lock bit, init bit */
  63.     if (hqx->protect & 0x40) info.protect = 1;  /* copy protect bit */
  64.     bcopy(hqx->dlen, info.dlen, 8);             /* dlen, rlen */
  65.     mtim = time2mac(time(0));
  66.     bcopy(&mtim, info.mtim, 4);
  67.     bcopy(&mtim, info.ctim, 4);
  68.     info.uploadvers = '\201';
  69.     info.readvers = '\201';
  70.  
  71.     /* calculate MacBinary CRC */
  72.     crc = calc_mb_crc(&info, 124, 0);
  73.     info.crc[0] = (char) (crc >> 8);
  74.     info.crc[1] = (char) crc;
  75.  
  76.     /* Create the .bin file and write the info to it */
  77.     unixify(hqx_block->name);
  78. /*    sprintf(binfname, "%s/%s%s", dir, hqx_block->name, ext); */
  79.     /* We don't need .bin extension for opening on NeXT. */
  80.     sprintf(binfname, "%s/%s", dir, hqx_block->name);    /* ## io ## */
  81.     fprintf(verbose,
  82.         "Converting     %-30s type = \"%4.4s\", author = \"%4.4s\"\n",
  83.         hqx_block->name, info.type, info.auth);
  84.     if ((binfile = fopen(binfname, "w")) == NULL)
  85.         error("Cannot open %s", binfname);
  86.     check_hqx_crc(calc_crc, "File header CRC mismatch in %s", binfname);
  87. /*  This is where info fork is written to a file. */
  88. /*    fwrite(&info, sizeof(info), 1, binfile); */    /* ## io ## */
  89.  
  90.     /* Get a couple of items we'll need later */
  91.     bcopy(info.dlen, hqx_datalen, 4);
  92.     *hqx_datalen = mac2long(*hqx_datalen);
  93.     bcopy(info.rlen, hqx_rsrclen, 4);
  94.     *hqx_rsrclen = mac2long(*hqx_rsrclen);
  95.     bcopy(info.type, type, 4);
  96.     }
  97.  
  98. /* This routine reads the header of a bin file and appropriately twiddles it,
  99.     creates the .hqx file, and puts the info into the .hqx file.
  100.     Output is hqx_datalen, hqx_rsrclen, type, hqxfname, hqxfile */
  101.  
  102. bin_to_hqx_hdr(hqx_datalen, hqx_rsrclen)
  103. ulong *hqx_datalen, *hqx_rsrclen;
  104. {   register byte *hqx_ptr, *hqx_end;
  105.     register ulong calc_crc;
  106.     hqx_buf *hqx_block;
  107.     hqx_header *hqx;
  108.     info_header info;
  109.     extern word magic[];
  110.     extern FILE *verbose;
  111.     extern char **hqxnames_left;
  112.     extern char *ext;
  113.  
  114.     strcpy(binfname, *hqxnames_left++);
  115.     if (!(binfile = fopen(binfname, "r"))) {
  116.         /* Maybe we are supposed to figure out the suffix ourselves? */
  117.         strcat(binfname, ext);
  118.         if (!(binfile = fopen(binfname, "r")))
  119.             error("Cannot open %s", binfname);
  120.         }
  121.     if (!fread(&info, sizeof(info), 1, binfile))
  122.         error("Unexpected EOF in header of %s", binfname);
  123.  
  124.     /* stuff the info header into the hqx header */
  125.     hqx_block = (hqx_buf *) buf_ptr;
  126.     hqx_block->nlen = info.nlen;
  127.     strncpy(hqx_block->name, info.name, info.nlen);
  128.     hqx = (hqx_header *) (hqx_block->name + hqx_block->nlen);
  129.     hqx->version  = 0;
  130.     bcopy(info.type, hqx->type, 9);             /* type, author, flags */
  131.     if (info.protect = 1) hqx->protect = 0;     /* protect bit: 0x40 */
  132.     else hqx->protect = 0;
  133.     bcopy(info.dlen, hqx->dlen, 8);             /* dlen, rlen */
  134.  
  135.     /* Create the .hqx file and write the info to it */
  136.     strncpy(hqxfname, info.name, info.nlen);
  137.     hqxfname[info.nlen] = '\0';
  138.     unixify(hqxfname);
  139.     fprintf(verbose,
  140.         "Converting     %-30s type = \"%4.4s\", author = \"%4.4s\"\n",
  141.         hqxfname, info.type, info.auth);
  142.  
  143.     calc_crc = 0;
  144.     hqx_ptr = (byte *) hqx_block;
  145.     hqx_end = hqx_ptr + hqx_block->nlen + sizeof(hqx_header);
  146.     while (hqx_ptr < hqx_end)
  147.         calc_crc = (((calc_crc&0xff) << 8) | *hqx_ptr++) ^ magic[calc_crc >> 8];
  148.     calc_crc = ((calc_crc&0xff) << 8) ^ magic[calc_crc >> 8];
  149.     calc_crc = ((calc_crc&0xff) << 8) ^ magic[calc_crc >> 8];
  150.     buf_ptr = hqx_end;
  151.     write_hqx_crc(calc_crc);
  152.  
  153.     /* Get a couple of items we'll need later */
  154.     bcopy(info.dlen, hqx_datalen, 4);
  155.     *hqx_datalen = mac2long(*hqx_datalen);
  156.     bcopy(info.rlen, hqx_rsrclen, 4);
  157.     *hqx_rsrclen = mac2long(*hqx_rsrclen);
  158.     }
  159.  
  160.  
  161. /* This routine copies bytes from the decoded input stream to the output.  
  162.     It also pads to a multiple of 128 bytes on the output, which is part
  163.     of the .bin format */
  164. word hqx_to_bin_fork(nbytes)
  165. register ulong nbytes;
  166. {   register byte *c;
  167.     register ulong calc_crc;
  168.     register int c_length;
  169.     ulong extra_bytes;
  170.     extern word magic[];
  171.  
  172.     extra_bytes = 127 - (nbytes+127)%128; /* pad fork to mult of 128 bytes */
  173.     calc_crc = 0;
  174.     for (;;) {
  175.         c = buf_ptr;
  176.         c_length = (c + nbytes > buf_end) ? buf_end - c : nbytes;
  177.         nbytes -= c_length;
  178.         fwrite(c, sizeof(byte), c_length, binfile);
  179.         while (c_length--)
  180.             calc_crc = (((calc_crc&0xff) << 8) | *c++) ^ magic[calc_crc >> 8];
  181.         if (!nbytes) break;
  182.         fill_hqxbuf();
  183.         }
  184.     buf_ptr = c;
  185. /* We don't need zero padding, because we are saving just the data fork. */
  186. /*    while (extra_bytes--) putc(0, binfile); */    /* ## io ## */
  187.     calc_crc = ((calc_crc&0xff) << 8) ^ magic[calc_crc >> 8];
  188.     calc_crc = ((calc_crc&0xff) << 8) ^ magic[calc_crc >> 8];
  189.     return (word) calc_crc;
  190.     }
  191.  
  192. /* This routine copies bytes from the input stream to the encoded output.  
  193.     It also pads to a multiple of 128 bytes on the input, which is part
  194.     of the .bin format */
  195. word bin_to_hqx_fork(nbytes)
  196. register ulong nbytes;
  197. {   register byte *c;
  198.     register ulong calc_crc;
  199.     register int c_length;
  200.     ulong extra_bytes;
  201.     extern word magic[];
  202.  
  203.     extra_bytes = 127 - (nbytes+127)%128; /* pad fork to mult of 128 bytes */
  204.     calc_crc = 0;
  205.     for (;;) {
  206.         c = buf_ptr;
  207.         c_length = (c + nbytes > buf_end) ? buf_end - c : nbytes;
  208.         nbytes -= c_length;
  209.         fread(c, sizeof(byte), c_length, binfile);
  210.         buf_ptr += c_length;
  211.         while (c_length--)
  212.             calc_crc = (((calc_crc&0xff) << 8) | *c++) ^ magic[calc_crc >> 8];
  213.         if (!nbytes) break;
  214.         empty_hqxbuf();
  215.         }
  216.     buf_ptr = c;
  217.  
  218.     fseek(binfile, extra_bytes, 1);
  219.     calc_crc = ((calc_crc&0xff) << 8) ^ magic[calc_crc >> 8];
  220.     calc_crc = ((calc_crc&0xff) << 8) ^ magic[calc_crc >> 8];
  221.     return (word) calc_crc;
  222.     }
  223.  
  224. /* Essentials for Binhex 8to6 run length encoding */
  225. #define RUNCHAR 0x90
  226. #define MAXRUN 255
  227. #define IS_LEGAL <0x40
  228. #define ISNT_LEGAL >0x3f
  229. #define DONE 0x7F /* tr68[':'] = DONE, since Binhex terminator is ':' */
  230. #define SKIP 0x7E /* tr68['\n'|'\r'] = SKIP, i. e. end of line char.  */
  231. #define FAIL 0x7D /* character illegal in binhex file */
  232.  
  233. byte tr86[] =
  234.         "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr"; 
  235. byte tr68[] = {
  236.     FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  237.     FAIL, FAIL, SKIP, FAIL, FAIL, SKIP, FAIL, FAIL,
  238.     FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  239.     FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  240.     FAIL, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
  241.     0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, FAIL, FAIL,
  242.     0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, FAIL,
  243.     0x14, 0x15, DONE, FAIL, FAIL, FAIL, FAIL, FAIL,
  244.     0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
  245.     0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, FAIL,
  246.     0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, FAIL,
  247.     0x2C, 0x2D, 0x2E, 0x2F, FAIL, FAIL, FAIL, FAIL,
  248.     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, FAIL,
  249.     0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, FAIL, FAIL,
  250.     0x3D, 0x3E, 0x3F, FAIL, FAIL, FAIL, FAIL, FAIL,
  251.     FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  252.     FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  253.     FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  254.     FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  255.     FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  256.     FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  257.     FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  258.     FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  259.     FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  260.     FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  261.     FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  262.     FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  263.     FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  264.     FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  265.     FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  266.     FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  267.     FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  268.     };
  269.  
  270. /*
  271.  *  This procedure transparently reads and decodes the hqx input.  It does run 
  272.  *  length and 6 to 8 decoding.
  273.  */
  274. #define READING 0
  275. #define SKIPPING 1
  276. #define FIND_START_COLON 2
  277.  
  278. fill_hqxbuf()
  279. {   register ulong c, nibble;
  280.     register int not_in_a_run = TRUE, state68;
  281.     register byte *fast_buf, *fast_line;
  282.     static int status = FIND_START_COLON;
  283.  
  284.     buf_ptr = fast_buf = buf_start;
  285.     fast_line = line_ptr;
  286.     state68 = save_state;
  287.     nibble = save_nibble;
  288.     if (save_run_length > 0) {
  289.         c = save_run_length;
  290.         save_run_length = 0;
  291.         goto continue_run;
  292.         }
  293.     while (fast_buf < buf_end) {
  294.         next_char:
  295.         if ((c = *fast_line++) ISNT_LEGAL) {
  296.             if (c == DONE) break;
  297.             next_line:
  298.             if (!fgets(line_start, MAXLINE, hqxfile) && !new_in_hqx_file())
  299.                 if (status == FIND_START_COLON) exit(0);
  300.         else error("Premature EOF in %s\n", hqxfname);
  301.             line_ptr = line_start;
  302.             scan_line:
  303.             fast_line = line_ptr;
  304.         while ((*fast_line = tr68[*fast_line]) IS_LEGAL) fast_line++;
  305.         c = *fast_line;
  306.             switch (status) {
  307.             case READING:
  308.                 if (c == SKIP && fast_line == line_end) break;
  309.                 if (c == DONE) {
  310.                     status = FIND_START_COLON;
  311.                     break;
  312.                     }
  313.                 status = SKIPPING;
  314.                 goto next_line;
  315.             case SKIPPING:
  316.                 if (c == SKIP && fast_line == line_end) {
  317.                     status = READING;
  318.                     break;
  319.                     }
  320.         /*  GMT, 1/9/90: Added this clause to avoid losing the last
  321.          *  line if it was preceeded by a skipped line.  */
  322.                 if (c == DONE) {
  323.                     status = FIND_START_COLON;
  324.                     break;
  325.                     }
  326.                 goto next_line;
  327.             case FIND_START_COLON:
  328.                 if (*line_start == DONE) {
  329.                     status = READING;
  330.                     line_ptr++;
  331.                     goto scan_line;
  332.                     }
  333.                 goto next_line;
  334.                 }
  335.             fast_line = line_ptr;
  336.             c = *fast_line++;
  337.             }
  338.  
  339.         /* Finally, we have the next 6 bits worth of data */
  340.         switch (state68++) {
  341.         case 0:
  342.             nibble = c;
  343.             goto next_char;
  344.         case 1:
  345.             nibble = (nibble << 6) | c;
  346.             c = nibble >> 4;
  347.             break;
  348.         case 2:
  349.             nibble = (nibble << 6) | c;
  350.             c = (nibble >> 2) & 0xff;
  351.             break;
  352.         case 3:
  353.             c = (nibble << 6) & 0xff | c;
  354.             state68 = 0;
  355.             break;
  356.             }
  357.         if (not_in_a_run)
  358.             if (c != RUNCHAR) *fast_buf++ = c;
  359.             else {not_in_a_run = FALSE; goto next_char;}
  360.         else {
  361.             if (c--) {
  362.                 not_in_a_run = buf_end - fast_buf;
  363.                 if (c > not_in_a_run) {
  364.                     save_run_length = c - not_in_a_run;
  365.                     c = not_in_a_run;
  366.                     }
  367.                 continue_run:
  368.                 not_in_a_run = fast_buf[-1];
  369.                 while (c--) *fast_buf++ = not_in_a_run;
  370.                 }
  371.             else *fast_buf++ = RUNCHAR;
  372.             not_in_a_run = TRUE;
  373.             }
  374.         }
  375.     total_bytes += fast_buf - buf_ptr;
  376.     buf_start[-1] = fast_buf[-1];
  377.     line_ptr = fast_line;
  378.     save_state = state68;
  379.     save_nibble = nibble;
  380.     }
  381.  
  382.  
  383. new_in_hqx_file()
  384. {   char *hqx_ext;
  385.     extern char **hqxnames_left;
  386.     if (*hqxnames_left[0] == '\0' || *hqxnames_left[0] == '-') return FALSE;
  387.     strcpy(hqxfname, *hqxnames_left++);
  388.     hqx_ext = hqxfname + strlen(hqxfname) - 4;
  389.     if (!strcmp(hqx_ext, ".hqx"))
  390.         if (!freopen(hqxfname, "r", hqxfile))
  391.             error("Cannot open %s\n", hqxfname);
  392.             else;
  393.     else {
  394.         if (!freopen(hqxfname, "r", hqxfile)) {
  395.             hqx_ext += 4;
  396.             strcpy(hqx_ext, ".hqx");
  397.             if (!freopen(hqxfname, "r", hqxfile)) {
  398.                 error("Cannot find %s\n", hqxfname);
  399.             }
  400.         }
  401.       }
  402.     fgets(line_start, MAXLINE, hqxfile);
  403.     return TRUE;
  404.     }
  405.  
  406. /*
  407.  *  This procedure transparently encodes and writes the hqx output.  
  408.  *  It does run length and 8 to 6 encoding.
  409.  */
  410. empty_hqxbuf()
  411. {   register ulong c, nibble, last_c;
  412.     register byte *fast_buf, *fast_line;
  413.     register int state86, dont_look_for_runs = FALSE, run_length;
  414.     extern int maxlines;
  415.  
  416.     run_length = save_run_length;
  417.     last_c = buf_start[-1];
  418.     fast_buf = buf_start;
  419.     fast_line = line_ptr;
  420.     state86 = save_state;
  421.     nibble = save_nibble;
  422.     while (fast_buf < buf_ptr) {
  423.         c = *fast_buf++;
  424.         if (dont_look_for_runs) dont_look_for_runs = FALSE;
  425.         else if (last_c == c &&  run_length < MAXRUN) {run_length++; continue;}
  426.         else {
  427.             if (run_length >1) {
  428.                 --fast_buf;
  429.                 if (run_length == 2 && last_c != RUNCHAR) c = last_c;
  430.                 else {
  431.                     c = RUNCHAR;
  432.                     *--fast_buf = run_length;
  433.                     dont_look_for_runs = TRUE;
  434.                     }
  435.                 run_length = 1;
  436.                 }
  437.             else last_c = c;
  438.             if (c == RUNCHAR && !dont_look_for_runs) {
  439.                 *--fast_buf = 0;
  440.                 dont_look_for_runs = TRUE;
  441.                 }
  442.             }
  443.  
  444.         if (fast_line == line_end) {
  445.             if (line_count++ == maxlines) new_out_hqx_file();
  446.             fputs(line_start, hqxfile);
  447.             fast_line = line_start;
  448.             }
  449.  
  450.         switch (state86++) {
  451.         case 0:
  452.             *fast_line++ = tr86[ c >> 2 ];
  453.             nibble = (c << 4) & 0x3f;
  454.             break;
  455.         case 1:
  456.             *fast_line++ = tr86[ (c >> 4) | nibble ];
  457.             nibble = (c << 2) & 0x3f;
  458.             break;
  459.         case 2:
  460.             *fast_line++ = tr86[ (c >> 6) | nibble ];
  461.             if (fast_line == line_end) {
  462.                 if (line_count++ == maxlines) new_out_hqx_file();
  463.                 fputs(line_start, hqxfile);
  464.                 fast_line = line_start;
  465.                 }
  466.             *fast_line++ = tr86[ c & 0x3f ];
  467.             state86 = 0;
  468.             break;
  469.             }
  470.         }
  471.     save_run_length = run_length;
  472.     buf_start[-1] = last_c;
  473.     buf_ptr = buf_start;
  474.     line_ptr = fast_line;
  475.     save_state = state86;
  476.     save_nibble = nibble;
  477.     }
  478.  
  479. new_out_hqx_file()
  480. {   char filename[NAMELEN + 7];
  481.     extern int maxlines;
  482.     fprintf(hqxfile, "<<< End of Part %2d >>>\n", file_count);
  483.     fclose(hqxfile);
  484.     file_count++;
  485.     if (maxlines) sprintf(filename, "%s%02d.hqx", hqxfname, file_count);
  486.     else sprintf(filename, "%s.hqx", hqxfname);
  487.     if ((hqxfile = fopen(filename, "w")) == NULL)
  488.         error("Can't create %s", filename);
  489.     if (file_count > 1)
  490.         fprintf(hqxfile, "<<< Start of Part %2d >>>\n", file_count);
  491.     else fprintf(hqxfile, "(This file must be converted with BinHex 4.0)\n\n");
  492.     line_count = 3;
  493.     }
  494.  
  495. check_hqx_crc(calc_crc, msg, name)
  496. word calc_crc;
  497. char msg[], name[];
  498. {   word read_crc;
  499.     if (buf_ptr >= buf_end) fill_hqxbuf();
  500.     read_crc = *buf_ptr++ << 8;
  501.     if (buf_ptr >= buf_end) fill_hqxbuf();
  502.     read_crc |= *buf_ptr++;
  503.     if (read_crc != calc_crc) error(msg, name);
  504.     }
  505.  
  506. write_hqx_crc(calc_crc)
  507. word calc_crc;
  508. {   if (buf_ptr == buf_end) empty_hqxbuf();
  509.     *buf_ptr++ = calc_crc >> 8;
  510.     if (buf_ptr == buf_end) empty_hqxbuf();
  511.     *buf_ptr++ = calc_crc;
  512.     }
  513.  
  514. un_hqx(unpit_flag)
  515. int unpit_flag;
  516. {   char type[4];
  517.     ulong hqx_datalen, hqx_rsrclen;
  518.     word un_pit();
  519.     int unpitting, bytes_read;
  520.     word calc_crc;
  521.     extern char **hqxnames_left;
  522.  
  523.     hqxfile = fopen("/dev/null", "r");
  524.     line_end = line_start + HQXLINELEN;
  525.     buf_end = buf_start + HQXBUFLEN;
  526.     for (;;) {
  527.         total_bytes = 0;
  528.         line_ptr = line_start;
  529.         line_ptr[0] = SKIP;
  530.         save_state = 0;
  531.         save_run_length = 0;
  532.  
  533.         hqx_to_bin_hdr(type, &hqx_datalen, &hqx_rsrclen); /* binfname */
  534.  
  535.         unpitting = unpit_flag && !strcmp(type, "PIT ");
  536.         if (unpitting) {
  537.             fclose(binfile);
  538.             unlink(binfname);
  539.             bytes_read = total_bytes - (buf_end - buf_ptr);
  540.             calc_crc = un_pit();
  541.             bytes_read = total_bytes - (buf_end - buf_ptr) - bytes_read;
  542.             if (bytes_read != hqx_datalen)
  543.                 fprintf(stderr,
  544.                   "Warning - Extraneous characters ignored in %s\n", binfname);
  545.             }
  546.  
  547.     /* This is where the data fork is written to the file. Keep this. */
  548.         else calc_crc = hqx_to_bin_fork(hqx_datalen);
  549.         check_hqx_crc(calc_crc, "File data CRC mismatch in %s", binfname);
  550.  
  551.     /* This is where the resource fork is written to the file. */
  552. /*
  553.         calc_crc = hqx_to_bin_fork(hqx_rsrclen);
  554.         check_hqx_crc(calc_crc, "File rsrc CRC mismatch in %s", binfname);
  555. */    /* ## io ## */
  556.         if (!unpitting) fclose(binfile);
  557.         }
  558.     }
  559.  
  560. re_hqx()
  561. {   word calc_crc;
  562.     ulong hqx_datalen, hqx_rsrclen;
  563.     extern char **hqxnames_left;
  564.     extern int maxlines;
  565.     line_end = line_start + HQXLINELEN;
  566.     buf_end = buf_start + HQXBUFLEN;
  567.     while (*hqxnames_left[0] != '-') {
  568.         hqxfile = fopen("/dev/null", "w");
  569.         line_count = maxlines;
  570.         file_count = 0;
  571.         line_ptr = line_start;
  572.         *line_ptr++ = ':';
  573.         strcpy(line_end, "\n");
  574.         buf_ptr = buf_start;
  575.         save_state = 0;
  576.         save_run_length = 1;
  577.  
  578.         bin_to_hqx_hdr(&hqx_datalen, &hqx_rsrclen);   /* calculates hqxfname */
  579.  
  580.         calc_crc = bin_to_hqx_fork(hqx_datalen);
  581.         write_hqx_crc(calc_crc);
  582.  
  583.         calc_crc = bin_to_hqx_fork(hqx_rsrclen);
  584.         write_hqx_crc(calc_crc);
  585.         *buf_ptr = !buf_ptr[-1];      /* To end a run and to get the last */
  586.         buf_ptr++;
  587.         empty_hqxbuf();                 /* stray bits, temporarily add a char */
  588.         if (save_state != 2) --line_ptr;
  589.         if (line_ptr == line_end) {
  590.             fputs(line_start, hqxfile);
  591.             line_ptr = line_start;
  592.             }
  593.         strcpy(line_ptr, ":\n");
  594.         fputs(line_start, hqxfile);
  595.         fclose(hqxfile);
  596.         }
  597.     }
  598.